﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using CellWarzGame;
using CellWarzGame.Actors;
using CellWarzGame.Collections;
using SpectrEngine.Framework;
using CellWarzGame.Screens;

namespace CellWarzGame.AI
{
    class AI
    {
        static float attackDistance = 50.0f;
        static Random rand = new Random();
        public AI()
        {
        }

        static public Vector2 Decide(Cell cell)
        {
            if (cell is Virus)
                return new Vector2(0,0);

            if (cell.Action == Cell.ActionState.Death)
                return new Vector2(0, 0);



            IList<DrawableGameNode> cellList = cell.Game.Services.GetService<ICellListService>().GetNearest(cell.Position);
        

            List<Vector2> dirs = new List<Vector2>();

            if (cell.Action == Cell.ActionState.Death)
                return new Vector2(0, 0);
            
            //set type strength
            float chaseStrength = 0;
            float nearStrength = 0;
            float fleeStrength = 0;
            if (cell.cellType == Cell.CellType.Monk)
            {
                chaseStrength = 3.0f;
                nearStrength = 1.0f;
                fleeStrength = 2.0f;
            }
            if (cell.cellType == Cell.CellType.Punk)
            {
                chaseStrength = 5.0f;
                nearStrength = 2.0f;
                fleeStrength = 0.5f;
            }
            if (cell.cellType == Cell.CellType.Skunk)
            {
                chaseStrength = 4.0f;
                nearStrength = 0.5f;
                fleeStrength = 1.0f;
            }

            //add vectors for frends and skunks
            foreach (Cell other in cellList)
            {
                if (other == cell) continue;
                Vector2 vec = other.Position - cell.Position;
                float dist;
                dist = vec.Length();
                vec = vec / (vec.Length()+0.01f);
                if (other.side == cell.side)
                {
                    if (dist < cell.toClose)
                        dirs.Add(-nearStrength * vec);
                    if (dist > cell.toFar)
                        dirs.Add(nearStrength * vec);
                }
                if (dist < cell.toClose / 4)
                {
                    if (vec.X == float.NaN || vec.Y == float.NaN)
                        vec = new Vector2((float)rand.NextDouble(), (float)rand.NextDouble());

                    if (other != cell.enemy)
                    {
                        dirs.Add(-5 * vec);
                    }
                    if (dist < cell.toClose / 8)
                    {
                        dirs.Add(-20 * vec);
                    }
                }
                /*else
                {
                    if (other.cellType == Cell.CellType.Skunk)
                    {
                        float skunkFact;

                        if (dist > cell.toFar)
                            skunkFact = 0;
                        else if (dist > (cell.toFar + cell.toClose) / 2)
                            skunkFact = -0.3f;
                        else if (dist > cell.toClose)
                            skunkFact = -0.6f;
                        else
                            skunkFact = -1.0f;

                        dirs.Add(skunkFact * vec);
                    }
                }*/
            }
            
            Vector2 follow = new Vector2(0,0);
            if (cell.enemy == cell) cell.enemy = null;
            if (cell.enemy != null)
                follow = new Vector2(cell.enemy.Position.X - cell.Position.X, cell.enemy.Position.Y - cell.Position.Y);
            else
                cell.Action = Cell.ActionState.Wander;

            float maxDist = (cell.toFar + cell.toClose);
            if (cell.Action == Cell.ActionState.Attack)
            {
                if (cell.enemy != null || 
                    ((cell.enemy != null) &&( cell.enemy.hp < 0)))
                {
                    if (follow.Length() > AI.attackDistance)
                        cell.Action = Cell.ActionState.Chase;

                    follow.Normalize();
                    dirs.Add(chaseStrength * 3.0f * follow);

                    if (cell.enemy.invunlerableTime > 0 || cell.enemy.hp == 0)
                        cell.Action = Cell.ActionState.Wander;
                }

                if (cell.hp <= 1)
                    cell.Action = Cell.ActionState.Flee;
            }
            else if (cell.Action == Cell.ActionState.Chase)
            {
                if (cell.enemy != null || ((cell.enemy != null) && (cell.enemy.hp < 0)))
                {
                    if (follow.Length() < AI.attackDistance)
                        cell.Action = Cell.ActionState.Attack;

                    follow.Normalize();
                    dirs.Add(chaseStrength * follow);

                    if (cell.enemy.side == cell.side)
                        cell.Action = Cell.ActionState.Wander;
                }
                else
                    cell.Action = Cell.ActionState.Wander;

                if (follow.Length() > maxDist)
                    cell.Action = Cell.ActionState.Wander;

                if (cell.hp <= 1)
                    cell.Action = Cell.ActionState.Flee;
            }
            else if (cell.Action == Cell.ActionState.Flee)
            {
                follow = follow * -1;

                if (cell.hp > 25 ||                     
                    cell.enemy != null ||
                    ((cell.enemy != null) && cell.enemy.hp < 0) || 
                    follow.Length() > (cell.toFar + cell.toClose) / 2)
                {
                    cell.enemy = null;
                    cell.Action = Cell.ActionState.Wander;
                }

                follow.Normalize();
                dirs.Add(fleeStrength * follow);
            }
            else if (cell.Action == Cell.ActionState.Wander)
            {
                Cell enemy = null;
                foreach (Cell other in cellList)
                {
                    if (other.side != cell.side)
                        if ((other.Position - cell.Position).Length() < maxDist && other != cell)
                            if (rand.NextDouble() > 0.98)
                                if (other.invunlerableTime <= 0)
                                    enemy = other;
                }

                if (enemy != null)
                {
                    cell.enemy = enemy;
                    cell.Action = Cell.ActionState.Chase;
                }
            }
            else
            {
            }

            Vector2 sum = new Vector2(0, 0);
            foreach (Vector2 v in dirs)
            {
                if (!(float.IsNaN(v.X) || float.IsNaN(v.Y)))
                    sum += v;
            }

            if (sum.Length() == 0)
            {
                sum.X = (float)Math.Sin(cell.angle)/4;
                sum.Y = (float)Math.Cos(cell.angle) / 4;
                cell.angle += (float)rand.NextDouble() * 0.2f - 0.1f;
            }
            else 
                sum.Normalize();

            return sum;
        }

        #region Tail Segment
        public static float AngleNorm(float a)
        {
            while (a >= Math.PI * 2)
                a -= (float)Math.PI * 2;
            while (a <= 0)
                a += (float)Math.PI * 2;
            return a;
        }
        public static float AngleDiff(float a, float b)
        {
            float sign = 1;
            a = AngleNorm(a);
            b = AngleNorm(b);

            if (Math.Abs(a - b) < Math.PI)
            {
                return b - a;
            }

            if (a < b)
            {
                a += (float)Math.PI * 2;
                sign = -1;
            }

            return (a - b) * sign;
        }
        public static void TailSegmentAct(Cell cell)
        {
            if (cell.enemy != null)
            {
                Vector2 follow;
                float far, near, stop;

                if (cell.enemy.cellType == Cell.CellType.Virus)
                {
                    follow = (cell.enemy.Position + new Vector2((float)Math.Cos(cell.enemy.Rotation) * -50, (float)Math.Sin(cell.enemy.Rotation) * -50)) - cell.Position;
                    cell.Translate(follow);

                    cell.Rotate(AngleDiff(cell.Rotation /*+ (float)Math.PI * 4.0f / 5.0f*/, (float)Math.Atan2(follow.Y, follow.X)) / 2);
                    return;
                }
                else
                {
                    follow = (cell.enemy.Position - cell.Position);
                    far = 100; near = 50; stop = 20;
                }

                Vector2 norm = Vector2.Normalize(follow);

                if (follow.Length() > far)
                {
                    cell.Translate((follow - norm * 50) * 0.5f);
                }
                else if (follow.Length() > near)
                {
                    cell.Translate((follow - norm * 50) * 0.5f);
                }
                else if (follow.Length() < stop)
                {
                    cell.Translate(-0.5f * follow);
                }

                cell.Rotate(AngleDiff(cell.Rotation /*+ (float)Math.PI * 4.0f / 5.0f*/, (float)Math.Atan2(follow.Y, follow.X)) / 2);

            }

        }
        #endregion
    }
}
